;=================================================
; variables in common lisp
; :DOC: Common Lisp supports two kinds of variables: lexical and dynamic.
;

;=================================================
; sample 1
; testing `let'
;
(defun let-test ()

 ; foo function
 (defun foo (x)
   (format t "Parameter: ~a~%" x)      ; |<------ x is argument 
   (let ((x 2))                        ; |
     (format t "Outer LET: ~a~%" x)    ; | |<---- x is 2
     (let ((x 3))                      ; | |
       (format t "Inner LET: ~a~%" x)) ; | | |<-- x is 3
     (format t "Outer LET: ~a~%" x))   ; | |
   (format t "Parameter: ~a~%" x))     ; |


 (foo 12)

 ; dotimes introduces a variable
 (dotimes (x 10)
  (format t "~a: ~a, ~a, ~a~%"

   x
   
   (let ((x 100)
         (y (+ x 10)))
    (list x y))

   (let* ((x 100)
          (y1 (+ x 10)))
    (list x y1))

   (let ((x 100))
    (let ((y2 (+ x 10)))
    (list x y2))
   )
  )
 )

 )


;=================================================
; sample 2
; testing lexical closures
(defun test-closures ()

 ; defining functional parameter
 (defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))
 (format t "fn call 1 = ~a~%fn call 2 = ~a~%"
  (funcall *fn*)
  (funcall *fn*)
 )
 )

;=================================================
; sample 3
; testing general assignment
; :DOC: assignment types:
; Simple variable:    (setf x 10) 
; Array:              (setf (aref a 0) 10)
; Hash table:         (setf (gethash 'key hash) 10)
; Slot named 'field': (setf (field o) 10)
(defun general-assignment-test ()`
 (let ((x 10))
  (setf x (+ x 1))
  (format t "x = ~a~%" x)
  )

 (setq y 12)
 (setf y (+ y 1))
 (format t "y = ~a~%" y)

 (let ((a ( 1 2 3)))
  (format t "aref a[0] = ~a~%" (aref a 1))
 )
 )

;=================================================
; main test function
;
(defun test ()

 ; 1
 ;(let-test)

 ; 2
 ;(test-closures)

 ; 3
 (general-assignment-test)
 )

;=================================================
; entry point
;
(defun main ()
 
 ; print startup banner
 (format t "variables test~%=====~%")

 ; test function
 (test)

 ; leaves program to the shell
 (exit)
)

(main)

